'use strict';

const { Sequelize } = require('sequelize');
const config = require('../app/config');
const { logger, color } = require('../app/utils/logger.utils');
const { emailTool } = require('../app/utils');
const fs = require('fs');
const path = require('path');

const mysql = config.database;
const { host, port, database, username, password, pool } = mysql;
const { max: poolMax, min: poolMin, idle: poolIdle, acquire: poolAcquire } = pool;
const CHARSET = mysql.charset || 'utf8mb4';
const ALERT_EMAILS = config.environment.alert?.receiveEmails?.split(',').map((e) => e.trim()) || [];

const RETRY_CONFIG = {
    maxRetries: 3,
    initialDelay: 1000,
    delayMultiplier: 2,
    retryableErrors: ['ETIMEDOUT', 'ECONNREFUSED', 'ECONNRESET', 'ENETUNREACH', 'Connection lost', 'Failed to connect'],
};

let sequelize;
let dbConnectResult = { success: false, totalCost: 0, retryCount: 0 };

// 创建Sequelize实例
try {
    sequelize = new Sequelize(database, username, password, {
        host,
        port,
        dialect: 'mysql',
        dialectOptions: {
            charset: CHARSET,
            supportBigNumbers: true,
            bigNumberStrings: false,
            ...mysql.dialectOptions,
        },
        pool: {
            max: poolMax,
            min: poolMin,
            idle: poolIdle,
            acquire: poolAcquire,
            evict: mysql.pool.evict || 10000,
        },
        logging: (sql) => logger.debug(`[SQL] ${sql}`, { metadata: {} }),
        timezone: '+08:00',
        retry: {
            max: 3, // 最大重试次数
            match: [
                /ETIMEDOUT/,
                /ECONNREFUSED/,
                /ECONNRESET/,
                /ENETUNREACH/,
                /EHOSTUNREACH/,
                /EPIPE/,
                /EAI_AGAIN/,
                /SequelizeConnectionError/,
                /SequelizeConnectionRefusedError/,
                /SequelizeHostNotFoundError/,
                /SequelizeHostNotReachableError/,
                /SequelizeInvalidConnectionError/,
                /SequelizeConnectionTimedOutError/,
                /SequelizeConnectionAcquireTimeoutError/,
            ],
        },
    });
    logger.debug(`${color.blue}📌 Sequelize 实例创建成功（版本：${Sequelize.version}）${color.reset}`, {
        metadata: {},
    });

    // 🔴 修复：Sequelize 6.x 正确监听连接错误的方式
    // 方式1：使用 authenticate() 方法测试连接并捕获错误
    const testConnection = async () => {
        try {
            await sequelize.authenticate();
            logger.info(`${color.green}✅ 数据库连接测试成功${color.reset}`, { metadata: {} });
        } catch (err) {
            const alertContent = `
                <p>🚨 [紧急] CorpHR数据库连接异常</p>
                <p>时间：${new Date().toLocaleString()}</p>
                <p>数据库：${database}</p>
                <p>连接地址：${host}:${port}</p>
                <p>错误详情：${err.message}</p>
                <p>影响：系统无法操作数据库，核心功能不可用</p>
                <p>解决方案：</p>
                <p>1. 检查MySQL服务是否正常运行</p>
                <p>2. 检查网络连接是否通畅</p>
                <p>3. 查看MySQL连接数是否超限</p>
            `;
            ALERT_EMAILS.forEach((email) => {
                emailTool
                    .sendNotice(email, '[紧急] CorpHR数据库连接异常告警', alertContent)
                    .catch((mailErr) =>
                        logger.error(`❌ 数据库异常告警邮件发送失败：${mailErr.message}`, { metadata: {} }),
                    );
            });
            throw err; // 重新抛出错误以便上层处理
        }
    };

    // 将测试连接函数暴露出去
    sequelize.testConnection = testConnection;
} catch (err) {
    logger.error(`${color.red}❌ Sequelize 实例创建失败：${err.message}${color.reset}`, { metadata: {} });
    // 实例创建失败告警
    const alertContent = `
        <p>🚨 [紧急] CorpHR数据库实例创建失败</p>
        <p>时间：${new Date().toLocaleString()}</p>
        <p>数据库：${database}</p>
        <p>错误详情：${err.message}</p>
        <p>影响：服务无法启动</p>
        <p>解决方案：核对数据库配置（账号、密码、地址）</p>
    `;
    ALERT_EMAILS.forEach((email) => {
        emailTool
            .sendNotice(email, '[紧急] CorpHR数据库实例创建失败', alertContent)
            .catch((mailErr) => logger.error(`❌ 实例创建告警邮件发送失败：${mailErr.message}`, { metadata: {} }));
    });
    process.exit(1);
}

// 判断错误是否可重试
const isRetryableError = (error) => {
    if (!error) return false;

    const errorMessage = error.message || '';
    const errorCode = error.code || '';

    return RETRY_CONFIG.retryableErrors.some(
        (retryableError) => errorMessage.includes(retryableError) || errorCode.includes(retryableError),
    );
};

// 导入数据库模型
const importModels = () => {
    const modelsDir = path.join(__dirname, 'models');

    if (!fs.existsSync(modelsDir)) {
        logger.warn(`${color.yellow}⚠️ 模型目录不存在: ${modelsDir}${color.reset}`, { metadata: {} });
        return {};
    }

    try {
        // 使用现有的 init-models.js 文件来初始化模型
        const initModels = require('./models/init-models');

        // 初始化所有模型并建立关联关系
        const models = initModels(sequelize);

        // 记录导入的模型信息
        const modelNames = Object.keys(models);
        logger.info(`${color.green}📦 数据库模型初始化完成，共 ${modelNames.length} 个模型${color.reset}`, {
            metadata: {},
        });

        // 输出每个模型的详细信息
        modelNames.forEach((modelName) => {
            const model = models[modelName];
            const tableName = model.tableName || modelName;
            const attributes = Object.keys(model.rawAttributes || {});

            logger.debug(`${color.blue}   📊 模型: ${modelName} (表: ${tableName})${color.reset}`, { metadata: {} });
            logger.debug(`${color.blue}     字段: ${attributes.length} 个${color.reset}`, { metadata: {} });

            // 输出关联关系
            const associations = Object.keys(model.associations || {});
            if (associations.length > 0) {
                logger.debug(`${color.blue}     关联: ${associations.join(', ')}${color.reset}`, { metadata: {} });
            }
        });

        // 将模型挂载到 sequelize 实例上，方便全局访问
        sequelize.models = models;

        return models;
    } catch (err) {
        logger.error(`${color.red}❌ 模型初始化失败: ${err.message}${color.reset}`, { metadata: {} });

        // 尝试回退到手动导入方式
        logger.warn(`${color.yellow}⚠️ 尝试使用手动导入方式...${color.reset}`, { metadata: {} });

        const models = {};
        const modelFiles = fs
            .readdirSync(modelsDir)
            .filter((file) => file.endsWith('.js') && file !== 'index.js' && file !== 'init-models.js');

        modelFiles.forEach((file) => {
            try {
                const modelPath = path.join(modelsDir, file);
                const modelFunc = require(modelPath);

                if (modelFunc && typeof modelFunc === 'function') {
                    const modelName = path.basename(file, '.js');
                    // 调用模型函数，传入 sequelize 和 DataTypes
                    const model = modelFunc(sequelize, sequelize.constructor);
                    models[modelName] = model;
                    logger.debug(`${color.blue}📦 手动导入模型: ${modelName}${color.reset}`, { metadata: {} });
                }
            } catch (modelErr) {
                logger.error(`${color.red}❌ 手动导入模型失败 ${file}: ${modelErr.message}${color.reset}`, {
                    metadata: {},
                });
            }
        });

        if (Object.keys(models).length > 0) {
            sequelize.models = models;
            logger.info(`${color.green}📦 手动导入完成，共 ${Object.keys(models).length} 个模型${color.reset}`, {
                metadata: {},
            });
        }

        return models;
    }
};

// ... existing code ...

// 连接数据库主函数
const connectDatabase = async () => {
    const startTime = Date.now();
    let retryCount = 0;

    while (retryCount <= RETRY_CONFIG.maxRetries) {
        try {
            logger.info(`${color.blue}🔄 尝试连接数据库 (第${retryCount + 1}次)...${color.reset}`, { metadata: {} });

            // 测试数据库连接
            await sequelize.testConnection();

            const totalCost = Date.now() - startTime;

            // 获取连接池状态
            const poolStatus = sequelize.connectionManager.pool
                ? {
                      size: sequelize.connectionManager.pool.size,
                      available: sequelize.connectionManager.pool.available,
                      using: sequelize.connectionManager.pool.using,
                      waiting: sequelize.connectionManager.pool.waiting,
                  }
                : { size: 0, available: 0, using: 0, waiting: 0 };

            dbConnectResult = {
                success: true,
                totalCost,
                retryCount,
                poolStatus,
                message: `数据库连接成功，耗时 ${totalCost}ms`,
            };

            logger.info(`${color.green}✅ 数据库连接成功！耗时: ${totalCost}ms${color.reset}`, { metadata: {} });

            // 导入模型
            const models = importModels();

            // 同步数据库表结构（可选，根据需求决定是否启用）
            if (process.env.NODE_ENV === 'development') {
                try {
                    await sequelize.sync({ alter: true });
                    logger.info(`${color.green}🔄 数据库表结构同步完成${color.reset}`, { metadata: {} });
                } catch (syncErr) {
                    logger.warn(`${color.yellow}⚠️ 数据库表结构同步失败: ${syncErr.message}${color.reset}`, {
                        metadata: {},
                    });
                }
            }

            return dbConnectResult;
        } catch (error) {
            retryCount++;
            const currentCost = Date.now() - startTime;

            if (retryCount <= RETRY_CONFIG.maxRetries && isRetryableError(error)) {
                const delay = RETRY_CONFIG.initialDelay * Math.pow(RETRY_CONFIG.delayMultiplier, retryCount - 1);
                logger.warn(
                    `${color.yellow}⚠️ 连接失败 (${retryCount}/${RETRY_CONFIG.maxRetries})，${delay}ms后重试...${color.reset}`,
                    { metadata: {} },
                );
                logger.warn(`${color.yellow}错误详情: ${error.message}${color.reset}`, { metadata: {} });

                await new Promise((resolve) => setTimeout(resolve, delay));
                continue;
            }

            // 达到最大重试次数或不可重试错误
            dbConnectResult = {
                success: false,
                totalCost: currentCost,
                retryCount: retryCount - 1,
                error: error.message,
                message: `数据库连接失败，重试 ${retryCount - 1} 次`,
            };

            logger.error(`${color.red}❌ 数据库连接最终失败: ${error.message}${color.reset}`, { metadata: {} });

            // 发送告警邮件
            const alertContent = `
                <p>🚨 [紧急] CorpHR数据库连接最终失败</p>
                <p>时间：${new Date().toLocaleString()}</p>
                <p>数据库：${database}</p>
                <p>连接地址：${host}:${port}</p>
                <p>重试次数：${retryCount - 1}</p>
                <p>总耗时：${currentCost}ms</p>
                <p>错误详情：${error.message}</p>
                <p>影响：系统无法启动</p>
                <p>解决方案：</p>
                <p>1. 检查MySQL服务状态</p>
                <p>2. 检查网络连接</p>
                <p>3. 检查数据库配置</p>
            `;

            ALERT_EMAILS.forEach((email) => {
                emailTool
                    .sendNotice(email, '[紧急] CorpHR数据库连接最终失败', alertContent)
                    .catch((mailErr) =>
                        logger.error(`❌ 最终失败告警邮件发送失败：${mailErr.message}`, { metadata: {} }),
                    );
            });

            return dbConnectResult;
        }
    }
};

module.exports = { connectDatabase, sequelize };
